package com.tinem.platform.web.auth.login.impl;

import cn.hutool.core.util.StrUtil;
import com.baidu.fsg.uid.UidGenerator;
import com.tinem.platform.module.pojo.enums.rbac.LoginType;
import com.tinem.platform.module.starter.jpa.entity.rbac.RbacAuthorities;
import com.tinem.platform.module.starter.jpa.entity.rbac.RbacUser;
import com.tinem.platform.module.starter.jpa.repository.rbac.RbacAuthoritiesRepository;
import com.tinem.platform.module.starter.jpa.repository.rbac.RbacUserRepository;
import com.tinem.platform.web.auth.login.LoginService;
import com.tinem.platform.web.auth.login.oauth2.Oauth2Server;
import com.tinem.platform.web.auth.page.LoginUserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.stream.Collectors;

/**
 * @author fzh
 * @version v1
 * @program: platform
 * @className LoginServiceImpl
 * @description TODO
 * @site
 * @company
 * @create 2020-09-03 13:43
 */
@Service("userDetailsService")
public class PlatformLoginServiceImpl implements LoginService {

    @Autowired
    RbacUserRepository rbacUserRepository;
    @Autowired
    RbacAuthoritiesRepository rbacAuthoritiesRepository;
    @Autowired
    private UidGenerator uidGenerator;

    @Override
    @Transactional(rollbackOn = Exception.class,value = Transactional.TxType.REQUIRES_NEW)
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        RbacUser user = rbacUserRepository.findFirstByAccount(username);
        LoginType loginType = LoginType.ACCOUNT_PASSWORD;
        if(user == null){
            user = rbacUserRepository.findFirstByEmail(username);
            loginType = LoginType.EMAIL_PASSWORD;
        }
        if(user == null) {
            user = rbacUserRepository.findFirstByMobileAndCountryMobileCode(username,"86");
            loginType = LoginType.MOBILE_PASSWORD;
        }
        if(user == null) {
            throw new UsernameNotFoundException("account not find:"+username);
        }
        LoginUserInfo login = userToLogin(user);
        login.setLoginType(loginType);
        return login;
    }

    @Override
    public String findUserByEmail(String email) {
        RbacUser user = rbacUserRepository.findFirstByEmail(email);
        if(user == null){
            return null;
        }
        return user.getId();
    }

    @Override
    public String findUserByMobile(String countryMobileCode, String mobile) {
        RbacUser user = rbacUserRepository.findFirstByMobileAndCountryMobileCode(mobile,countryMobileCode);
        if(user == null){
            return null;
        }
        return user.getId();
    }

    @Override
    public String findUserByAccount(String account) {
        RbacUser user = rbacUserRepository.findFirstByAccount(account);
        if(user == null){
            return null;
        }
        return user.getId();
    }

    @Override
    @Transactional(rollbackOn = Exception.class,value = Transactional.TxType.REQUIRES_NEW)
    public LoginUserInfo getLoginUser(String userId) {
        RbacUser user = rbacUserRepository.getOne(userId);
        LoginUserInfo login = userToLogin(user);
        return login;
    }

    @Override
    @Transactional(rollbackOn = Exception.class,value = Transactional.TxType.REQUIRES_NEW)
    public String bindUser(Oauth2Server oauth2Server, OAuth2User oAuth2User) {
        if(StrUtil.isNotEmpty(oauth2Server.getEmail(oAuth2User))){
            return bindUserByEmail(oauth2Server.getEmail(oAuth2User),"86",oauth2Server.getMobile(oAuth2User),oauth2Server.getName(oAuth2User),oauth2Server.getNickName(oAuth2User));
        }
        if(StrUtil.isNotEmpty(oauth2Server.getMobile(oAuth2User))){
            return bindUserByMobile(oauth2Server.getEmail(oAuth2User),"86",oauth2Server.getMobile(oAuth2User),oauth2Server.getName(oAuth2User),oauth2Server.getNickName(oAuth2User));
        }
        return addUser(oauth2Server.getEmail(oAuth2User),"86",oauth2Server.getMobile(oAuth2User),oauth2Server.getName(oAuth2User),oauth2Server.getNickName(oAuth2User));
    }

    @Override
    public String bindUserByEmail(String email,String countryMobileCode, String mobile, String name, String nickname) {
        RbacUser user = rbacUserRepository.findFirstByEmail(email);
        if(user == null){
            return addUser(email,countryMobileCode,mobile,name,nickname);
        }
        return user.getId();
    }

    @Override
    public String bindUserByMobile(String email,String countryMobileCode, String mobile, String name, String nickname) {
        RbacUser user = rbacUserRepository.findFirstByMobileAndCountryMobileCode(countryMobileCode,mobile);
        if(user == null){
            return addUser(email,countryMobileCode,mobile,name,nickname);
        }
        return user.getId();
    }

    @Override
    @Transactional(rollbackOn = Exception.class,value = Transactional.TxType.REQUIRES_NEW)
    public String addUser(String email,String countryMobileCode,String mobile,String name,String nickname) {
        RbacUser user = new RbacUser();
        user.setId(uidGenerator.getUID());
        user.setEmail(email);
        user.setCountryMobileCode(countryMobileCode);
        user.setMobile(mobile);
        user.setName(name);
        user.setNickName(nickname);
        rbacUserRepository.saveAndFlush(user);
        return user.getId();
    }

    public LoginUserInfo userToLogin(RbacUser user){
        LoginUserInfo loginUserInfo = new LoginUserInfo();
        loginUserInfo.setNickName(user.getNickName());
        loginUserInfo.setSex(user.getSex());
        loginUserInfo.setAccount(user.getAccount());
        loginUserInfo.setName(user.getName());
        loginUserInfo.setHeadImage(user.getHeadImage());
        loginUserInfo.setCountryMobileCode(user.getCountryMobileCode());
        loginUserInfo.setMobile(user.getMobile());
        loginUserInfo.setEmail(user.getEmail());
        loginUserInfo.setLockedDate(user.getLockedDate());
        loginUserInfo.setExpiredDate(user.getExpiredDate());
        loginUserInfo.setUsername(String.valueOf(user.getId()));
        loginUserInfo.setEnabled(user.getEnabled().isEnabled());
        loginUserInfo.setPassword(user.getPassword());
        loginUserInfo.setPasswordErrorNumber(user.getPasswordErrorNumber());
        loginUserInfo.setPasswordErrorTime(user.getPasswordErrorTime());
        loginUserInfo.setPasswordExpired(user.getPasswordExpired());
        loginUserInfo.setAuthorities(
                rbacAuthoritiesRepository.findByUser(user.getId())
                        .stream()
                        .map(RbacAuthorities::getAuthorities)
                        .map(SimpleGrantedAuthority::new)
                        .collect(Collectors.toSet())
        );
        return loginUserInfo;
    }
}
